using System.Collections;  // 引用用于协程的命名空间
using System.Collections.Generic;  // 引用用于列表的命名空间
using UnityEngine;  // 引用Unity的基础功能
using UnityEngine.EventSystems;  // 引用事件系统，用于处理UI事件
using UnityEngine.UI;  // 引用UI组件，比如Text, Button等
using WebGLSupport;  // 引用WebGL相关的支持功能

public class ChatSample : MonoBehaviour
{
    /// <summary>
    /// 聊天设置
    /// </summary>
    [SerializeField] private ChatSetting m_ChatSettings;

    #region UI相关
    /// <summary>
    /// 聊天面板UI
    /// </summary>
    [SerializeField] private GameObject m_ChatPanel;  // 显示聊天内容的面板

    /// <summary>
    /// 输入框UI，用于用户输入消息
    /// </summary>
    [SerializeField] public InputField m_InputWord;  // 用户输入消息的输入框

    /// <summary>
    /// 返回信息的文本UI
    /// </summary>
    [SerializeField] private Text m_TextBack;  // 用于显示返回信息的文本框

    /// <summary>
    /// 音频源，用于播放语音
    /// </summary>
    [SerializeField] private AudioSource m_AudioSource;  // 用于播放语音或音效的组件

    /// <summary>
    /// 提交消息的按钮
    /// </summary>
    [SerializeField] private Button m_CommitMsgBtn;  // 提交按钮，用于发送消息

    #endregion

    #region 配置项
    /// <summary>
    /// 动画控制器
    /// </summary>
    [SerializeField] private Animator m_Animator;  // 用于控制角色动画的Animator组件

    /// <summary>
    /// 是否启用语音模式，默认启用
    /// </summary>
    [Header("是否启用语音模式，默认启用")]
    [SerializeField] private bool m_IsVoiceMode = true;  // 是否启用语音模式，控制是否进行语音识别和播放

    /// <summary>
    /// 是否创建语音模式的内容
    /// </summary>
    [Header("是否创建语音模式的内容")]
    [SerializeField] private bool m_CreateVoiceMode = false;  // 是否创建语音模式的内容，控制是否创建语音相关内容

    #endregion

    private void Awake()
    {
        m_CommitMsgBtn.onClick.AddListener(delegate { SendData(); });  // 绑定按钮点击事件，点击按钮时调用 SendData 方法
        RegistButtonEvent();  // 注册语音输入按钮的事件监听
        InputSettingWhenWebgl();  // 配置 WebGL 的输入设置
    }

    #region 信息处理

    /// <summary>
    /// WebGL时设置输入支持
    /// </summary>
    private void InputSettingWhenWebgl()
    {
#if UNITY_WEBGL
        m_InputWord.gameObject.AddComponent<WebGLSupport.WebGLInput>();  // 如果是WebGL平台，添加WebGL输入支持
#endif
    }

    /// <summary>
    /// 发送消息
    /// </summary>
    public void SendData()
    {
        if (m_InputWord.text.Equals(""))  // 如果输入框为空，返回
            return;

        if (m_CreateVoiceMode)  // 如果启用语音模式
        {
            CallBack(m_InputWord.text);  // 调用回调处理语音输入
            m_InputWord.text = "";  // 清空输入框
            return;
        }

        // 添加到聊天历史
        m_ChatHistory.Add(m_InputWord.text);  
        // 获取输入的消息
        string _msg = m_InputWord.text;

        // 调用聊天模型发送消息并处理返回结果
        m_ChatSettings.m_ChatModel.PostMsg(_msg, CallBack);  

        m_InputWord.text = "";  // 清空输入框
        m_TextBack.text = "正在思考...";  // 显示正在思考的提示

        // 设置动画状态，显示思考动画
        SetAnimator("state", 1);
    }

    /// <summary>
    /// 发送自定义消息
    /// </summary>
    /// <param name="_postWord"></param>
    public void SendData(string _postWord)
    {
        if (_postWord.Equals(""))  // 如果消息为空，返回
            return;

        if (m_CreateVoiceMode)  // 如果启用语音模式
        {
            CallBack(_postWord);  // 调用回调处理语音输入
            m_InputWord.text = "";  // 清空输入框
            return;
        }

        // 添加到聊天历史
        m_ChatHistory.Add(_postWord);
        // 获取自定义的消息
        string _msg = _postWord;

        // 调用聊天模型发送消息并处理返回结果
        m_ChatSettings.m_ChatModel.PostMsg(_msg, CallBack);

        m_InputWord.text = "";  // 清空输入框
        m_TextBack.text = "正在思考...";  // 显示正在思考的提示

        // 设置动画状态，显示思考动画
        SetAnimator("state", 1);
    }

    /// <summary>
    /// AI回复处理
    /// </summary>
    /// <param name="_response"></param>
    private void CallBack(string _response)
    {
        _response = _response.Trim();  // 去掉回复内容的前后空格
        m_TextBack.text = "";  // 清空返回文本框

        Debug.Log("收到AI回复：" + _response);  // 打印AI回复内容

        // 添加到聊天历史
        m_ChatHistory.Add(_response);

        if (!m_IsVoiceMode || m_ChatSettings.m_TextToSpeech == null)  // 如果不是语音模式或者没有TTS（文本转语音）
        {
            // 启动逐字显示效果
            StartTypeWords(_response);
            return;
        }

        // 如果是语音模式，进行文本转语音，并播放
        m_ChatSettings.m_TextToSpeech.Speak(_response, PlayVoice);
    }

    #endregion

    #region 语音处理
    /// <summary>
    /// 自动发送语音识别结果
    /// </summary>
    [SerializeField] private bool m_AutoSend = true;  // 是否自动发送识别到的文本

    /// <summary>
    /// 语音输入按钮
    /// </summary>
    [SerializeField] private Button m_VoiceInputBotton;  // 语音输入按钮

    /// <summary>
    /// 按钮文本
    /// </summary>
    [SerializeField] private Text m_VoiceBottonText;  // 语音按钮上的文字

    /// <summary>
    /// 录音提示
    /// </summary>
    [SerializeField] private Text m_RecordTips;  // 显示录音状态的文本

    /// <summary>
    /// 语音输入处理
    /// </summary>
    [SerializeField] private VoiceInputs m_VoiceInputs;  // 语音输入处理组件

    /// <summary>
    /// 注册按钮点击事件
    /// </summary>
    private void RegistButtonEvent()
    {
        if (m_VoiceInputBotton == null || m_VoiceInputBotton.GetComponent<EventTrigger>())
            return;

        EventTrigger _trigger = m_VoiceInputBotton.gameObject.AddComponent<EventTrigger>();  // 添加事件触发器组件

        // 监听按下事件，开始录音
        EventTrigger.Entry _pointDown_entry = new EventTrigger.Entry();
        _pointDown_entry.eventID = EventTriggerType.PointerDown;
        _pointDown_entry.callback = new EventTrigger.TriggerEvent();

        // 监听松开事件，停止录音
        EventTrigger.Entry _pointUp_entry = new EventTrigger.Entry();
        _pointUp_entry.eventID = EventTriggerType.PointerUp;
        _pointUp_entry.callback = new EventTrigger.TriggerEvent();

        // 设置事件回调
        _pointDown_entry.callback.AddListener(delegate { StartRecord(); });
        _pointUp_entry.callback.AddListener(delegate { StopRecord(); });

        // 添加事件监听
        _trigger.triggers.Add(_pointDown_entry);
        _trigger.triggers.Add(_pointUp_entry);
    }

    /// <summary>
    /// 开始录音
    /// </summary>
    public void StartRecord()
    {
        m_VoiceBottonText.text = "正在录音...";  // 显示录音中提示
        m_VoiceInputs.StartRecordAudio();  // 开始录音
    }

    /// <summary>
    /// 停止录音
    /// </summary>
    public void StopRecord()
    {
        m_VoiceBottonText.text = "点击按钮开始录音";  // 更新按钮文本
        m_RecordTips.text = "录音识别中...";  // 更新录音提示
        m_VoiceInputs.StopRecordAudio(AcceptClip);  // 停止录音并处理音频
    }

    /// <summary>
    /// 处理录音数据（语音转文本）
    /// </summary>
    private void AcceptData(byte[] _data)
    {
        if (m_ChatSettings.m_SpeechToText == null)
            return;

        m_ChatSettings.m_SpeechToText.SpeechToText(_data, DealingTextCallback);  // 调用语音识别功能
    }

    /// <summary>
    /// 处理录音后的音频数据
    /// </summary>
    private void AcceptClip(AudioClip _audioClip)
    {
        if (m_ChatSettings.m_SpeechToText == null)
            return;

        m_ChatSettings.m_SpeechToText.SpeechToText(_audioClip, DealingTextCallback);  // 调用语音识别功能
    }

    /// <summary>
    /// 处理语音识别的文本
    /// </summary>
    private void DealingTextCallback(string _msg)
    {
        m_RecordTips.text = _msg;  // 显示识别结果
        StartCoroutine(SetTextVisible(m_RecordTips));  // 3秒后清除识别文本

        // 自动发送或填入输入框
        if (m_AutoSend)
        {
            SendData(_msg);  // 自动发送识别的文本
            return;
        }

        m_InputWord.text = _msg;  // 将识别的文本填入输入框
    }

    private IEnumerator SetTextVisible(Text _textbox)
    {
        yield return new WaitForSeconds(3f);  // 等待3秒
        _textbox.text = "";  // 清空提示文本
    }

    #endregion

    #region 播放语音

    /// <summary>
    /// 播放语音并开始显示文本
    /// </summary>
    private void PlayVoice(AudioClip _clip, string _response)
    {
        m_AudioSource.clip = _clip;  // 设置音频源的音频剪辑
        m_AudioSource.Play();  // 播放音频
        Debug.Log("音频时长：" + _clip.length);  // 打印音频时长
        StartTypeWords(_response);  // 开始逐字显示文本
        SetAnimator("state", 2);  // 设置动画状态
    }

    #endregion

    #region 逐字显示文本

    [SerializeField] private float m_WordWaitTime = 0.2f;  // 每个字之间的等待时间
    [SerializeField] private bool m_WriteState = false;  // 控制文本显示状态

    /// <summary>
    /// 开始逐字显示文本
    /// </summary>
    private void StartTypeWords(string _msg)
    {
        if (_msg == "")
            return;

        m_WriteState = true;
        StartCoroutine(SetTextPerWord(_msg));  // 开始逐字显示
    }

    private IEnumerator SetTextPerWord(string _msg)
    {
        int currentPos = 0;
        while (m_WriteState)
        {
            yield return new WaitForSeconds(m_WordWaitTime);  // 每个字之间等待
            currentPos++;  // 显示下一个字
            m_TextBack.text = _msg.Substring(0, currentPos);  // 更新显示的文本

            m_WriteState = currentPos < _msg.Length;  // 控制是否继续显示文本
        }

        // 完成后恢复动画
        SetAnimator("state", 0);
    }

    #endregion

    #region 聊天历史

    [SerializeField] private List<string> m_ChatHistory;  // 存储聊天历史
    [SerializeField] private List<GameObject> m_TempChatBox;  // 存储临时聊天框

    [SerializeField] private GameObject m_HistoryPanel;  // 显示聊天历史的面板
    [SerializeField] private RectTransform m_rootTrans;  // 存放聊天项的容器

    [SerializeField] private ChatPrefab m_PostChatPrefab;  // 发送消息的Prefab
    [SerializeField] private ChatPrefab m_RobotChatPrefab;  // AI回复的Prefab

    [SerializeField] private ScrollRect m_ScroTectObject;  // 滚动视图

    /// <summary>
    /// 打开并加载聊天历史
    /// </summary>
    public void OpenAndGetHistory()
    {
        m_ChatPanel.SetActive(false);  // 隐藏聊天面板
        m_HistoryPanel.SetActive(true);  // 显示历史记录面板

        ClearChatBox();  // 清空当前聊天框
        StartCoroutine(GetHistoryChatInfo());  // 获取并显示聊天历史
    }

    /// <summary>
    /// 返回到聊天模式
    /// </summary>
    public void BackChatMode()
    {
        m_ChatPanel.SetActive(true);  // 显示聊天面板
        m_HistoryPanel.SetActive(false);  // 隐藏历史记录面板
    }

    /// <summary>
    /// 清空聊天框
    /// </summary>
    private void ClearChatBox()
    {
        while (m_TempChatBox.Count != 0)
        {
            if (m_TempChatBox[0])
            {
                Destroy(m_TempChatBox[0].gameObject);  // 删除临时聊天框中的项
                m_TempChatBox.RemoveAt(0);  // 从列表中移除
            }
        }
        m_TempChatBox.Clear();  // 清空临时聊天框列表
    }

    /// <summary>
    /// 获取并显示聊天历史
    /// </summary>
    private IEnumerator GetHistoryChatInfo()
    {
        yield return new WaitForEndOfFrame();  // 等待当前帧完成

        for (int i = 0; i < m_ChatHistory.Count; i++)
        {
            if (i % 2 == 0)  // 偶数索引为用户发送的消息
            {
                ChatPrefab _sendChat = Instantiate(m_PostChatPrefab, m_rootTrans.transform);  // 实例化发送消息的聊天框
                _sendChat.SetText(m_ChatHistory[i]);  // 设置消息内容
                m_TempChatBox.Add(_sendChat.gameObject);  // 添加到临时聊天框中
                continue;
            }

            ChatPrefab _reChat = Instantiate(m_RobotChatPrefab, m_rootTrans.transform);  // 实例化AI回复的聊天框
            _reChat.SetText(m_ChatHistory[i]);  // 设置AI回复内容
            m_TempChatBox.Add(_reChat.gameObject);  // 添加到临时聊天框中
        }

        // 强制更新布局
        LayoutRebuilder.ForceRebuildLayoutImmediate(m_rootTrans);
        StartCoroutine(TurnToLastLine());  // 滚动到底部
    }

    /// <summary>
    /// 滚动到聊天历史的最后一行
    /// </summary>
    private IEnumerator TurnToLastLine()
    {
        yield return new WaitForEndOfFrame();  // 等待当前帧完成
        m_ScroTectObject.verticalNormalizedPosition = 0;  // 滚动到底部
    }

    #endregion

    private void SetAnimator(string _para, int _value)
    {
        if (m_Animator == null)  // 如果Animator为空
            return;

        m_Animator.SetInteger(_para, _value);  // 设置动画参数
    }
}